package top.lunarye.modules.staff.service.impl;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import top.lunarye.modules.staff.entity.RoleEnum;
import top.lunarye.modules.staff.entity.Staff;
import top.lunarye.modules.staff.entity.dto.*;
import top.lunarye.modules.staff.mapper.StaffMapper;
import top.lunarye.modules.staff.service.IStaffService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import top.lunarye.utils.DigesterUtil;
import top.lunarye.utils.ExcelReadUtil;
import top.lunarye.utils.RestResponse;
import top.lunarye.utils.SystemCode;

import java.io.File;
import java.io.IOException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * <p>
 * 人员表 服务实现类
 * </p>
 *
 * @author lunar
 * @since 2021-07-13
 */
@Service("StaffServiceImpl")
@CacheConfig(cacheNames = "staff")
public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements IStaffService {

    @Autowired
    StaffMapper staffMapper;

    @Override
    @CacheEvict(value = "staff-list", key="'list'")
    public boolean addStaff(Staff staff) {
        QueryWrapper<Staff> wrapper = new QueryWrapper<>();
        wrapper.eq("user_name", staff.getUserName());
        final Staff selectStaff = staffMapper.selectOne(wrapper);
        if (selectStaff != null) {
            return false;
        }
        return staffMapper.insert(staff) == 1;
    }

    @Override
    @Cacheable(value = "staff-list", key="'list'", unless = "#result == null")
    public List<StaffSelectDTO> selectStaffList(){
        return staffMapper.selectStaffList();
    }

    @Override
    @Cacheable(value = "staff", key="#username", unless = "#result == null")
    public Staff selectStaffByUsername(String username) {
        QueryWrapper<Staff> wrapper = new QueryWrapper<>();
        wrapper.eq("user_name", username);
        return staffMapper.selectOne(wrapper);
    }

    @Override
    @CacheEvict(value = "staff-list", key="'list'")
    public RestResponse<String> addList(MultipartFile file) {
        String fileOriginName = file.getOriginalFilename();
        if (fileOriginName == null) {
            throw new UtilException("文件名存在错误");
        }
        String[] split = fileOriginName.split("\\.");
        if (split.length != 2)
            throw new UtilException("文件名存在错误");
        String fileName = split[0];
        String fileSuffix = "."+split[1];
        File tempFile = null;
        try {
            tempFile = File.createTempFile(fileName, fileSuffix);
            file.transferTo(tempFile);
            List<StaffExcelInsertDO> staffList = ExcelReadUtil.getStaffInfoListFromExcel(tempFile);
            List<Staff> insertList = new LinkedList<>();
            for (StaffExcelInsertDO insertStaff: staffList) {
               Staff staff = new Staff();
               BeanUtils.copyProperties(insertStaff, staff);
               if (staff.getUserPassword() == null || staff.getUserPassword().equals(""))
                   staff.setUserPassword("123456");
               if (insertStaff.getRole() == null)
                   staff.setRole(RoleEnum.student);
               else
                   staff.setRole(RoleEnum.getRoleEnum(insertStaff.getRole()));
               staff.setUserPassword(DigesterUtil.digestHaxWithSalt(staff.getUserPassword(), staff.getUserName()));
               insertList.add(staff);
            }
            try {
                int result = staffMapper.insertStaffList(insertList);
            } catch (Exception e) {
                throw new UtilException("请检查用户名的唯一性");
            }
            tempFile.deleteOnExit(); // 删除临时文件
        } catch (IOException e) {
            throw new UtilException("在读取文件时发生错误");
        } finally {
            if (tempFile != null)
                tempFile.delete();
        }
        return RestResponse.ok();
    }

    @Caching(evict = {
            @CacheEvict(value = "staff-list", key="'list'"),
            @CacheEvict(value = "staff", key = "#staff.userName")
    })
    public RestResponse updateStaff(StaffUpdateDTO staff, Staff loginStaff) {
        Staff selectStaff = staffMapper.selectById(staff.getId());
        if (selectStaff == null)
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), "没有权限进行该用户信息的修改");
        if (!selectStaff.getId().equals(loginStaff.getId()) &&
                loginStaff.getRole().getId().equals(RoleEnum.student.getId())) {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), "没有权限进行该用户信息的修改");
        }
        if (!staff.getUserName().equals(selectStaff.getUserName())) {
            throw new UtilException("不能修改用户名");
        }

        BeanUtils.copyProperties(staff, selectStaff);
        int result = staffMapper.updateById(selectStaff);
        if (result == 1) {
            return RestResponse.ok();
        } else {
            return RestResponse.fail(SystemCode.InnerError.getCode(), "更新时发生错误");
        }
    }

    @CacheEvict(value = "staff", key = "#loginStaff.userName")
    public RestResponse modifySelf(Staff loginStaff, UserInfoDTO userInfoDTO) {
        Staff staff = new Staff();
        BeanUtils.copyProperties(userInfoDTO, staff);
        staff.setId(loginStaff.getId());
        staff.setUserName(null);
        boolean result = updateById(staff);
        if (result) {
            return RestResponse.ok();
        } else {
            return RestResponse.fail(SystemCode.InnerError.getCode(), "更新时发生错误");
        }
    }

    @CacheEvict(value = "staff", key = "#loginStaff.userName")
    public RestResponse modifyPwd(Staff loginStaff, String pwd) {
        String digestHaxWithSalt = DigesterUtil.digestHaxWithSalt(pwd, loginStaff.getUserName());
        loginStaff.setUserPassword(digestHaxWithSalt);
        boolean result = updateById(loginStaff);
        if (result) {
            return RestResponse.ok();
        } else {
            return RestResponse.fail(SystemCode.InnerError.getCode(), "更新密码时发生错误");
        }
    }

    @CacheEvict(value = "staff-list", key="'list'")
    public RestResponse<String> disableStaff(Integer id, Staff loginStaff) {
        Staff disableStaff = staffMapper.selectById(id);
        if (disableStaff == null) {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), "没有权限对该账户进行禁用");
        }
        if (loginStaff.getRole().getId() >= disableStaff.getRole().getId()
                && !disableStaff.getRole().getId().equals(RoleEnum.admin.getId())) {
            UpdateWrapper<Staff> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", id);
            updateWrapper.set("is_disable", 1 );
            int update = staffMapper.update(null, updateWrapper);
            if (update == 1) {
                return RestResponse.ok();
            } else {
                return RestResponse.fail(SystemCode.InnerError.getCode(), "禁用账户时发生错误");
            }
        } else {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), "没有权限对该账户进行禁用");
        }
    }

    @CacheEvict(value = "staff-list", key="'list'")
    public RestResponse<String> enableStaff(Integer id, Staff loginStaff) {
        Staff disableStaff = staffMapper.selectById(id);
        if (disableStaff == null) {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), "没有权限对该账户进行启用");
        }
        if (loginStaff.getRole().getId() >= disableStaff.getRole().getId()
                && !disableStaff.getRole().getId().equals(RoleEnum.admin.getId())) {
            UpdateWrapper<Staff> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", id);
            updateWrapper.set("is_disable", 0);
            int update = staffMapper.update(null, updateWrapper);
            if (update == 1) {
                return RestResponse.ok();
            } else {
                return RestResponse.fail(SystemCode.InnerError.getCode(), "启用账户时发生错误");
            }
        } else {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), "没有权限对该账户进行启用");
        }
    }

    @CacheEvict(value = "staff-list", key="'list'")
    public RestResponse<String> deleteStaff(Integer id, Staff loginStaff) {
        Staff deleteStaff = staffMapper.selectById(id);
        if (deleteStaff == null) {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), "没有权限对该账户进行删除");
        }
        if (loginStaff.getRole().getId() >= deleteStaff.getRole().getId()
                && !deleteStaff.getRole().getId().equals(RoleEnum.admin.getId())) {
            int deleteById = staffMapper.deleteById(id);
            if (deleteById == 1) {
                return RestResponse.ok();
            } else {
                return RestResponse.fail(SystemCode.InnerError.getCode(), "删除账户时发生错误");
            }
        } else {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), "没有权限对该账户进行删除");
        }
    }
}
